package pub.wkq.auth.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;
import pub.wkq.auth.service.UsersService;
import pub.wkq.bo.RegisterOrLoginBO;
import pub.wkq.common.base.BaseInfoProperties;
import pub.wkq.common.result.JSONResult;
import pub.wkq.common.result.ResponseStatusEnum;
import pub.wkq.common.utils.JWTUtils;
import pub.wkq.common.utils.SMSUtils;
import pub.wkq.common.utils.SerializationUtils;
import pub.wkq.mq.SMSContentQO;
import pub.wkq.pojo.Users;
import pub.wkq.vo.UsersVO;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import java.util.UUID;

import static pub.wkq.api.mq.RabbitMQSMSConfig.*;

/**
 * 通行证控制器
 */
@RestController
@RequestMapping("passport")
@Slf4j
public class PassportController extends BaseInfoProperties {
    private final UsersService usersService;
    private final JWTUtils jwtUtils;
    private final RabbitTemplate rabbitTemplate;

    public PassportController(UsersService usersService, JWTUtils jwtUtils, RabbitTemplate rabbitTemplate) {
        this.usersService = usersService;
        this.jwtUtils = jwtUtils;
        this.rabbitTemplate = rabbitTemplate;
    }

    /**
     * 发送验证码
     */
    @GetMapping("sendCode")
    public JSONResult sendCode(String mobile, HttpServletRequest request) {
        //校验手机号
//        if (mobile == null || mobile.length() != 11) {
//            return JSONResult.errorMsg("手机号格式不正确");
//        }
        //生成 6 位验证码
        String code = (int) ((Math.random() * 9 + 1) * 100000) + "";
//        smsUtils.sendSms(mobile, code);
        //使用消息队列异步解耦发送短信
        SMSContentQO smsContentQO = new SMSContentQO();
        smsContentQO.setMobile(mobile);
        smsContentQO.setContent(code);
        //定义confirm回调
        rabbitTemplate.setConfirmCallback((/*相关联数据，参数*/correlationData,/*交换机是否成功接收到消息*/ ack,/*失败的原因*/ cause) -> {
            if (ack) {
                log.info("消息发送成功:correlationData({}),ack({}),cause({})", correlationData, ack, cause);
            } else {
                log.info("消息发送失败:correlationData({}),ack({}),cause({})", correlationData, ack, cause);
            }
        });
        //定义 return 回调
        rabbitTemplate.setReturnsCallback((returnCallback) -> {
            log.info("消息丢失:exchange({}),route({}),replyCode({}),replyText({}),message({})", returnCallback.getExchange(), returnCallback.getRoutingKey(), returnCallback.getReplyCode(), returnCallback.getReplyText(), returnCallback.getMessage());
        });
        //消息处理的类对象（对当前需要超时的 ttl 进行参数属性的设置）
        MessagePostProcessor messagePostProcessor = new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                MessageProperties messageProperties = message.getMessageProperties();
                messageProperties.setExpiration(String.valueOf(1000 * 60)); //可以给队列设置时间，也可以给消息设置时间，如果都设置了，会以较小的那个时间 为准。
                return message;
            }
        };
        rabbitTemplate.convertAndSend(SMS_EXCHANGE_NAME, SEND_EMAIL_ROUTING_KEY, SerializationUtils.serializeObject(smsContentQO), messagePostProcessor, new CorrelationData(UUID.randomUUID().toString()));
        log.info("手机号 {} 验证码 {}", mobile, code);
        //把验证码存入到 redis，用于后续的注册登录进行校验
        redis.set(MOBILE_SMSCODE + ":" + mobile, code, 60 * 5);
        return JSONResult.ok();
    }

    /**
     * 验证码一键登录注册
     */
    @PostMapping("loginOrRegister")
    public JSONResult loginOrRegister(@Valid @RequestBody RegisterOrLoginBO registerOrLoginBO) {
        String mobile = registerOrLoginBO.getMobile();
        String smsCode = registerOrLoginBO.getSmsCode();
        //1. 从 redis 中获得验证码进行校验判断是否匹配
        String redisCode = redis.get(MOBILE_SMSCODE + ":" + mobile);
        if (redisCode == null || !redisCode.equalsIgnoreCase(smsCode)) {
            return JSONResult.errorCustom(ResponseStatusEnum.SMS_CODE_ERROR);
        }
        //2. 根据 mobile 查询数据库，判断用户是否存在
        Users users = usersService.queryUserIsExist(mobile);
        //2.1 如果查询的用户为空，则表示没有注册过，则需要注册信息入库
        if (users == null) {
            log.info("用户 {} 未注册，开始注册", mobile);
            users = usersService.createUserAndInitResumeMQ(mobile);
        }
        //3. 保存用户 token，分布式会话到 redis 中,UUID 去掉 -
//        String uniqueToken = TOKEN_USER_PREFIX + SYMBOL_DOT + UUID.randomUUID().toString().replace("-", "");
//        redis.set(REDIS_USER_TOKEN + ":" + users.getId(), uniqueToken, 60 * 30);
        String serializeUser = SerializationUtils.serializeObject(users);
        String jwt = jwtUtils.createJwtWithPrefix(serializeUser, Long.valueOf(1000 * 60 * 60 * 24), TOKEN_USER_PREFIX);
        //4. 用户登录注册后，删除 redis 中的短信验证码
        redis.del(MOBILE_SMSCODE + ":" + mobile);
        //5. 返回用户信息给前端
        UsersVO usersVO = new UsersVO();
        BeanUtils.copyProperties(users, usersVO);
        usersVO.setUserToken(jwt);
        return JSONResult.ok(usersVO);
    }

    /**
     * 用户退出登录,后端只需要清除用户的 token 信息即可，前端也需要清除相关的用户信息
     */
    @PostMapping("logout")
    public JSONResult logout(String userId) {
        redis.del(REDIS_USER_TOKEN + ":" + userId);
        return JSONResult.ok();
    }
}
